<?php

/**
 * SimplifyPHP Framework
 *
 * This file is part of SimplifyPHP Framework.
 *
 * SimplifyPHP Framework is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * SimplifyPHP Framework is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @author Rodrigo Rutkoski Rodrigues, <rutkoski@gmail.com>
 */

/**
 * Application Controller
 *
 * @author Rodrigo Rutkoski Rodrigues <rutkoski@gmail.com>
 * @package Simplify_Kernel_Controller
 */
class ApplicationControllerImpl implements IApplicationController
{

  /**
   *
   * @var ICache
   */
  protected $cache;

  /**
   *
   * @var Config
   */
  protected $config;

  /**
   *
   * @var IRequest
   */
  protected $request;

  /**
   *
   * @var IResponse
   */
  protected $response;

  /**
   *
   * @var IRouter
   */
  protected $router;

  /**
   *
   * @var Language
   */
  protected $l10n;

  /**
   *
   * @var array
   */
  protected static $resp = array();

  /**
   *
   * @param $config
   * @return unknown_type
   */
  public function __construct(Config $config)
  {
    $this->config = $config;
  }

  public function initialize() {}

  /**
   * @return Language
   */
  public function getL10n()
  {
    return $this->l10n;
  }
  public function setL10n($l10n)
  {
    $this->l10n = $l10n;
  }

  /**
   * 
   * @return Config
   */
  public function getConfig()
  {
    return $this->config;
  }
  public function setConfig(Config $config)
  {
    $this->config = $config;
  }

  /**
   * 
   * @return IRouter
   */
  public function getRouter()
  {
    return $this->router;
  }
  public function setRouter(IRouter $router)
  {
    $this->router = $router;
  }

  /**
   * 
   * @return IRequest
   */
  public function getRequest()
  {
    return $this->request;
  }
  public function setRequest(IRequest $request)
  {
    $this->request = $request;
  }

  /**
   * 
   * @return IResponse
   */
  public function getResponse()
  {
    return $this->response;
  }
  public function setResponse(IResponse $response)
  {
    $this->response = $response;
  }

  /**
   * (non-PHPdoc)
   * @see simplify/kernel/api/IApplicationController#dispatch()
   */
  public function dispatch()
  {
    $route = $this->request->get('route');
    return $this->forward($route);
  }

  /**
   * (non-PHPdoc)
   * @see simplify/kernel/core/IApplicationController#forward($route)
   */
  public function forward($route)
  {
    $info = $this->router->parse($route);

    $this->createResponse();

    $path = $info->get('path');
    $controller = $info->get('controller');
    $action = $info->get('action');
    $params = $info->get('params');

    $cacheid = md5(serialize($this->config->get('locale') . $route));

    $cacheEnabled = !$this->request->get('post') && $this->config->get('{env}:cache:enabled', true);

    $configFile = sy_fix_path($path . '/' . $controller . '.yml');
    if ($cacheEnabled && file_exists($configFile)) {
      $config = new Config();
      $config->copyAllFromYAMLFile($configFile);
      $cacheEnabled = $config->get('disable_cache') !== true && $config->get('actions:' . $action . ':disable_cache') !== true;
    }

    try {
      if (! $cacheEnabled) {
        throw new CacheException('Caching is disabled');
      }

      $output = $this->getCache()->read($cacheid);
    }

    catch (CacheException $e) {
      $Controller = $this->factory($controller, $path);

      $output = $Controller->callActionArray($action, $params);

      if ($output === null) {
        $this->response->setLayout($Controller->getLayout());
        $this->response->setTemplate($Controller->getTemplate());
        $output = $this->response->render(false);
      }

      if ($cacheEnabled && $Controller->cacheEnabled) {
        $this->getCache()->write($cacheid, $output, $Controller->cacheTimeout);
      }
    }

    $output = $this->response->output($output);

    $this->restoreResponse();

    return $output;
  }

  protected function createResponse()
  {
    if ($this->response) {
      self::$resp[] = $this->response;
    }

    $class = $this->config->get('{env}:core:response:class', 'ResponseImpl');

    $resp = new $class;

    $this->setResponse($resp);
    $this->getResponse()->initialize();

    return $resp;
  }

  protected function restoreResponse()
  {
    $old = self::$resp;
    $resp = array_pop(self::$resp);
    if ($resp) $this->setResponse($resp);
    return $old;
  }

  /**
   * Factory an Action Controller object.
   *
   * @param string $name controller name
   * @return ActionController
   */
  protected function factory($controller, $path)
  {
    $class = Inflector::camelize($controller . '_controller');
    $Controller = new $class($path);
    return $Controller;
  }

  public function getCache()
  {
    if (empty($this->cache)) {
      $this->cache = new FileCache($this->config->get('{env}:cache:dir'));
    }
    return $this->cache;
  }

}

?>